继承与原型链 您所在的位置:网站首页 js 类定义 继承与原型链

继承与原型链

2023-12-11 14:29| 来源: 网络整理| 查看: 265

让我们来仔细看看幕后发生了什么。

如上所述,在 JavaScript 中,函数可以拥有属性。所有函数都有一个名为 prototype 的特殊属性。请注意,下面的代码是独立的(出于严谨,假设页面没有其他的 JavaScript 代码)。为获得最佳的学习体验,强烈建议你打开控制台,进入“console”标签页,复制并粘贴以下 JavaScript 代码,然后按回车键运行。(大多数 web 浏览器的开发者工具中都包含控制台。请参阅 Firefox 开发者工具、Chrome 开发者工具和 Edge 开发者工具,以了解详情。)

js

function doSomething() {} console.log(doSomething.prototype); // 你如何声明函数并不重要; // JavaScript 中的函数总有一个默认的 // 原型属性——有一个例外: // 箭头函数没有默认的原型属性: const doSomethingFromArrowFunction = () => {}; console.log(doSomethingFromArrowFunction.prototype);

如上所示,doSomething() 有一个默认的 prototype 属性(正如控制台所示)。运行这段代码后,控制台应该显示一个类似于下面的对象。

{ constructor: ƒ doSomething(), [[Prototype]]: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }

备注: Chrome 控制台使用 [[Prototype]] 来表示对象的原型,遵循规范的术语;Firefox 使用 。为了保持一致性,我们将使用 [[Prototype]]。

我们可以像下面这样,向 doSomething() 的原型添加属性。

js

function doSomething() {} doSomething.prototype.foo = "bar"; console.log(doSomething.prototype);

其结果为:

{ foo: "bar", constructor: ƒ doSomething(), [[Prototype]]: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }

我们现在可以使用 new 运算符来创建基于该原型的 doSomething() 的实例。要使用 new 运算符,只需像往常一样调用函数,只是要在前面加上 new。使用 new 运算符调用函数会返回一个函数的实例对象。然后可以在该对象上添加属性。

尝试以下代码:

js

function doSomething() {} doSomething.prototype.foo = "bar"; // 向原型上添加一个属性 const doSomeInstancing = new doSomething(); doSomeInstancing.prop = "some value"; // 向该对象添加一个属性 console.log(doSomeInstancing);

这会产生类似于下面的输出:

{ prop: "some value", [[Prototype]]: { foo: "bar", constructor: ƒ doSomething(), [[Prototype]]: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } } }

如上所示,doSomeInstancing 的 [[Prototype]] 是 doSomething.prototype。但是,这是做什么的呢?当你访问 doSomeInstancing 的属性时,运行时首先会查找 doSomeInstancing 是否有该属性。

如果 doSomeInstancing 没有该属性,那么运行时会在 doSomeInstancing.[[Prototype]](也就是 doSomething.prototype)中查找该属性。如果 doSomeInstancing.[[Prototype]] 有该属性,那么就会使用 doSomeInstancing.[[Prototype]] 上的该属性。

否则,如果 doSomeInstancing.[[Prototype]] 没有该属性,那么就会在 doSomeInstancing.[[Prototype]].[[Prototype]] 中查找该属性。默认情况下,任何函数的 prototype 属性的 [[Prototype]] 都是 Object.prototype。因此会在 doSomeInstancing.[[Prototype]].[[Prototype]](也就是 doSomething.prototype.[[Prototype]](也就是 Object.prototype))上查找该属性。

如果在 doSomeInstancing.[[Prototype]].[[Prototype]] 中没有找到该属性,那么就会在 doSomeInstancing.[[Prototype]].[[Prototype]].[[Prototype]] 中查找该属性。但是,这里有一个问题:doSomeInstancing.[[Prototype]].[[Prototype]].[[Prototype]] 不存在,因为 Object.prototype.[[Prototype]] 是 null。然后,只有在查找完整个 [[Prototype]] 链之后,运行时才会断言该属性不存在,并得出该属性的值为 undefined。

让我们在控制台中输入更多的代码:

js

function doSomething() {} doSomething.prototype.foo = "bar"; const doSomeInstancing = new doSomething(); doSomeInstancing.prop = "some value"; console.log("doSomeInstancing.prop: ", doSomeInstancing.prop); console.log("doSomeInstancing.foo: ", doSomeInstancing.foo); console.log("doSomething.prop: ", doSomething.prop); console.log("doSomething.foo: ", doSomething.foo); console.log("doSomething.prototype.prop:", doSomething.prototype.prop); console.log("doSomething.prototype.foo: ", doSomething.prototype.foo);

其结果如下:

doSomeInstancing.prop: some value doSomeInstancing.foo: bar doSomething.prop: undefined doSomething.foo: undefined doSomething.prototype.prop: undefined doSomething.prototype.foo: bar


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有